# -*- coding: utf-8 -*-
# coding:utf-8

import wejudge.kernel.general as kernel
import wejudge.apps.contest.models as ContestModel
import wejudge.kernel.problem as ProblemKernel
import ContestProvider as CP
import json
import os
import time
import datetime
import uuid
import xlrd

__author__ = 'lancelrq'


class ContestBody(CP.ContestProvider, ProblemKernel.ProblemBody, ProblemKernel.JudgeStatus):

    def __init__(self, request):
        kernel.ViewerFramework.__init__(self, request)
        self._navbar_action = 'contest'

    def contest_body(self, contest_id):
        """
        比赛首页
        :param contest_id:
        :return:
        """
        # if not self._check_login():
        #     return

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists()
            return

        if not self._check_permission(contest):
            self._send_error_contest_permission_denied()
            return

        is_referee = self._check_admin_permission(contest)

        self._template_file = "contest/body/index.html"
        self._context = {
            "is_referee": is_referee,
            "faq_counter": self._get_faq_counter(contest, is_referee),
            "contest": contest,
            'type': "index",
            'faqs': ContestModel.FAQ.objects.filter(contest=contest, is_private=False).order_by("-id")
        }

    def problems_list(self, contest_id):
        """
        比赛问题列表
        :param contest_id:
        :return:
        """
        # if not self._check_login():
        #     return

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists()
            return

        if not self._check_permission(contest):
            self._send_error_contest_permission_denied()
            return

        cproblem_list = contest.problemset.order_by('index').all()
        problem_list = []
        contest_problem_list = {}
        contest_problem_counter = {}
        user_solution_counter = {}
        user_solution_is_finish = {}
        for cproblem in cproblem_list:
            pid = cproblem.problem.id
            problem_list.append(cproblem.problem)
            contest_problem_list[pid] = cproblem
            contest_problem_counter[pid] = {
                'total': cproblem.submission,
                'ac': cproblem.accepted,
                'ratio': kernel.GeneralTools.ratio(cproblem.accepted, cproblem.submission)
            }
            sol = ContestModel.ContestSolution.objects.filter(contest=contest, problems=cproblem.problem, author=self._user_session.entity)
            if sol.exists():
                sol = sol[0]
                user_solution_counter[pid] = {
                    'total': sol.submission,
                    'ac': sol.accepted,
                    'ratio': kernel.GeneralTools.ratio(sol.accepted ,sol.submission)
                }
                if sol.accepted > 0:
                    user_solution_is_finish[pid] = True

        flag, desc = self._check_time_passed(contest)

        is_referee = self._check_admin_permission(contest)

        self._template_file = "contest/body/problem_list.html"
        self._context = {
            "type": "problem_list",
            "is_referee": is_referee,
            "faq_counter": self._get_faq_counter(contest, is_referee),
            "time_permission": flag,
            "contest": contest,
            "cproblem_list": cproblem_list,
            'contest_problem_counter': contest_problem_counter,
            'user_solution_counter': user_solution_counter,
            'user_solution_is_finish': user_solution_is_finish,
        }

    def show_contest_problem(self, contest_id, cproblem_id):
        """
        显示问题内容
        :param contest_id:
        :param problem_id:
        :return:
        """
        # if not self._check_login():
        #     return

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists()
            return

        if not self._check_permission(contest):
            self._send_error_contest_permission_denied()
            return

        is_referee = self._check_admin_permission(contest)
        if not is_referee:
            flag, times = self._check_time_passed(contest)
            if flag == -1:
                self._send_error_contest_not_start()
                return
            # elif flag == 1:
            #     self._send_error_contest_ended()
            #     return

        cproblem = contest.problemset.filter(id=cproblem_id)
        if not cproblem.exists():
            self._send_error_contest_problem_not_found()
            return
        cproblem = cproblem[0]

        if not super(ContestBody, self).show_problem(cproblem.problem.id, True):            # 调用上级题目展示
            return

        language_provider = kernel.GeneralTools._get_langauage_limit(contest.lang, cproblem.lang)

        self._context.update({
            'contest': contest,
            "is_referee": is_referee,
            "faq_counter": self._get_faq_counter(contest, is_referee),
            'cproblem': cproblem,
            'problem_index': cproblem.index,
            'language_provider': language_provider,
        })
        self._template_file = "problem/problem/view.html"

    def contest_submit_code(self, contest_id, problem_id):
        """
        提交代码
        :param contest_id:
        :param problem_id:
        :return:
        """
        self._action = kernel.const.VIEW_ACTION_JSON

        if not self._check_login(True):
            return

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists(True)
            return

        if not self._check_permission(contest):
            self._send_error_contest_permission_denied(True)
            return

        if contest.pause:
            self._result = kernel.RESTStruct(False, '当前比赛暂停评测，请等待评测开放')
            return

        flag, times = self._check_time_passed(contest)
        if flag == -1:
            self._send_error_contest_not_start(True)
            return
        elif flag == 1:
            self._send_error_contest_ended(True)
            return

        cproblem = contest.problemset.filter(problem__id=problem_id)
        if not cproblem.exists():
            self._send_error_contest_problem_not_found(True)
            return
        cproblem = cproblem[0]

        proc_result = self._save_submission(problem_id, True)     # 调用父类设置好的方法

        if proc_result.flag is True:                        # 如果父类方法处理成功
            status = proc_result.data
            status.callback = json.dumps({'provider': 'contest', 'id': contest.id})
            status.save()
            contest.judge_status.add(status)
            contest.save()
            sol = ContestModel.ContestSolution.objects.filter(contest=contest, problems=cproblem.problem, author=self._user_session.entity)
            if not sol.exists():
                sol = ContestModel.ContestSolution()
                sol.contest = contest
                sol.problems = cproblem.problem
                sol.author = self._user_session.entity
                sol.start_time = int(time.time())
                sol.save()
            else:
                sol = sol[0]
            sol.judge_status.add(status)
            sol.submission += 1
            sol.save()
            cproblem.submission += 1
            cproblem.save()

            proc_result.data = status.id
        else:
            proc_result.data = None

        self._result = proc_result

    def contest_status(self, contest_id, page=1, limit=50):
        """
        比赛评测状态显示
        :param contest_id:
        :param page:
        :param limit:
        :return:
        """
        # if not self._check_login():
        #     return

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists()
            return

        if not self._check_permission(contest):
            self._send_error_contest_permission_denied()
            return

        cproblem_list = contest.problemset.all()
        cproblem_manual_judge = []
        for cproblem in cproblem_list:
            if cproblem.judge_style > 0:
                cproblem_manual_judge.append(cproblem.problem.id)

        jst, dst = self._get_status_list(contest.judge_status)
        count = jst.count()
        pager = kernel.PagerProvider(count, limit, page, 'contest_status', 11, self._request.GET, contest.id)
        if count > 0:
            jdugestatus = jst.all()[pager.start_idx: pager.start_idx + limit]
        else:
            jdugestatus = []

        flag, desc = self._check_time_passed(contest)

        cproblem_list_id = {}
        cproblem_list_index = {}

        for ap in cproblem_list:
            cproblem_list_id[ap.problem.id] = ap.id
            cproblem_list_index[ap.problem.id] = ap.index
        for st in jdugestatus:
            st.cproblem_id = cproblem_list_id.get(st.problem.id, 0)
            st.cproblem_index = cproblem_list_index.get(st.problem.id, 0)

        is_referee = self._check_admin_permission(contest)

        self._template_file = "contest/body/status.html"
        self._context = {
            'contest': contest,
            "time_permission": flag,
            "is_referee": is_referee,
            "faq_counter": self._get_faq_counter(contest, is_referee),
            'cproblem_manual_judge': cproblem_manual_judge,
            'type': 'status',
            'pager': pager.render(),
            'status_list': jdugestatus,
            "flags": kernel.const.JUDGE_STATUS_FLAG_DESC.iteritems()
        }
        self._context.update(dst)

    def get_rank_board_datas(self, contest_id):
        """
        获取滚榜数据
        :param contest_id:
        :return:
        """
        self._action = kernel.const.VIEW_ACTION_JSON
        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists(True)
            return

        if not self._check_admin_permission(contest):
            self._result = kernel.RESTStruct(False, msg='性能限制，不对非管理用户开放本功能')
            return

        # 获取题目数据
        cproblem_list = contest.problemset.order_by("index")
        # 题目索引参照表
        cpindex_list = {}
        for cproblem in cproblem_list:
            cpindex_list[cproblem.problem.id] = cproblem.index

        judge_status_lte_1hr = contest.judge_status.order_by("id").filter(timestamp__lte=contest.end_time - 3600)
        judge_status_1hr = contest.judge_status.order_by("id").filter(timestamp__gt=contest.end_time - 3600)
        user_list = {}
        judge_status_list_lte_1hr = []
        judge_status_list_1hr = {}
        for status in judge_status_lte_1hr:
            if not user_list.has_key(status.author.id):
                if self._check_referees(contest, status.author.id):
                    continue
                user_list[str(status.author.id)] = {
                    "headimg": status.author.headimg,
                    "nickname": status.author.nickname,
                    "realname": status.author.realname,
                    "sex": status.author.sex
                }
            judge_status_list_lte_1hr.append({
                "id": status.id,
                "problem_id": status.problem.id,
                "user_id": status.author.id,
                "flag": status.flag,
                "timestamp": status.timestamp,
            })
        for status in judge_status_1hr:
            jitem = judge_status_list_1hr.get(str(status.author.id), {})
            pitem = jitem.get(str(status.problem.id), {
                'ac_flag': False,
                'ac_time': 0,
                'submit_count': 0,
                'ignore_count': 0,
            })
            if pitem['ac_flag'] is True:
                continue
            pitem['submit_count'] += 1
            if status.flag == 0:
                # AC
                pitem['ac_flag'] = True
                pitem['ac_time'] = status.timestamp - contest.start_time

            elif status.flag < 0 or status.flag > 8:
                pitem['ignore_count'] += 1

            jitem[str(status.problem.id)] = pitem
            judge_status_list_1hr[str(status.author.id)] = jitem

        self._result = kernel.RESTStruct(True, data={
            "start_time": contest.start_time,
            "problem_indexs": cpindex_list,
            "problem_list": [cproblem.problem.id for cproblem in cproblem_list],
            "judge_status_lte_1hr": judge_status_list_lte_1hr,
            "judge_status_1hr": judge_status_list_1hr,
            "user_list": user_list
        })

    def rank_board(self, contest_id):
        """
        滚榜
        :param contest_id:
        :return:
        """

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists()
            return

        if self._user_session.is_logined():
            is_referee = self._check_admin_permission(contest)
        else:
            is_referee = False

        cproblem_list = contest.problemset.order_by("index")

        self._template_file = "contest/body/board.html"
        self._context = {
            'contest': contest,
            "is_referee": is_referee,
            "faq_counter": self._get_faq_counter(contest, is_referee),
            'type': 'rank_list',
            "cproblem_list": cproblem_list,
        }

    def rank_list(self, contest_id):
        """
        排行榜
        :param contest_id:
        :return:
        """

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists()
            return

        if self._user_session.is_logined():
            is_referee = self._check_admin_permission(contest)
        else:
            is_referee = False
        rank_data = self._rank_list_counter(contest, is_referee)
        try:
            rank_data = json.loads(rank_data)
        except Exception, ex:
            rank_data = {}

        hr = contest.end_time - int(time.time())

        if -3600 < hr < 3600:
            onehr_stop_flag = 1
        elif hr < -3600:
            onehr_stop_flag = 2
        else:
            onehr_stop_flag = 0

        cproblem_list = contest.problemset.all()
        index_list = {}
        problem_to_cproblem = {}
        for cproblem in cproblem_list:
            index_list[str(cproblem.problem.id)] = cproblem.index
            problem_to_cproblem[str(cproblem.problem.id)] = cproblem.id

        self._template_file = "contest/body/ranklist.html"
        self._context = {
            'contest': contest,
            "is_referee": is_referee,
            "faq_counter": self._get_faq_counter(contest, is_referee),
            'type': 'rank_list',
            "index_list": index_list,
            "problem_to_cproblem": problem_to_cproblem,
            'rank_data': rank_data,
            '1hr_stop_flag': onehr_stop_flag
        }

    def faq(self, contest_id):
        """
        比赛问答
        :param contest_id:
        :return:
        """
        # if not self._check_login():
        #     return

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists()
            return

        if not self._check_permission(contest):
            self._send_error_contest_permission_denied()
            return

        is_referee = self._check_admin_permission(contest)
        if is_referee:
            faqs = ContestModel.FAQ.objects.filter(contest=contest, is_notice=0).order_by("-id")
            my_faqs = ContestModel.FAQ.objects.filter(contest=contest, is_notice=1, author=self._user_session.entity).order_by("-id")
        else:
            faqs = ContestModel.FAQ.objects.filter(contest=contest, is_private=False).order_by("-id")
            my_faqs = ContestModel.FAQ.objects.filter(contest=contest, author=self._user_session.entity).order_by("-id")


        flag, desc = self._check_time_passed(contest)
        self._template_file = "contest/body/faq.html"
        self._context = {
            'contest': contest,
            "time_permission": flag,
            "is_referee": is_referee,
            "faq_counter": self._get_faq_counter(contest, is_referee),
            'type': 'faq',
            'faqs': faqs,
            'my_faqs': my_faqs
        }

    def faq_new_msg(self, contest_id):
        """
        发起提问、公告
        :param contest_id:
        :return:
        """
        if not self._check_login():
            return

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists()
            return

        if not self._check_permission(contest):
            self._send_error_contest_permission_denied()
            return

        is_referee = self._check_admin_permission(contest)

        self._template_file = "contest/body/faq_editor.html"
        self._context = {
            'contest': contest,
            "is_referee": is_referee,
            "faq_counter": self._get_faq_counter(contest, is_referee),
            'type': 'faq'
        }

    def faq_reply_msg(self, contest_id, faq_id):
        """
        裁判回复提问
        :param contest_id:
        :return:
        """
        if not self._check_login():
            return

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists()
            return

        if not self._check_permission(contest):
            self._send_error_contest_permission_denied()
            return

        if not self._check_admin_permission(contest):
            self._send_error_contest_permission_denied()
            return

        faq = ContestModel.FAQ.objects.filter(id=faq_id)
        if not faq.exists():
            self._send_error_contest_faq_not_found()
            return

        is_referee = self._check_admin_permission(contest)

        self._template_file = "contest/body/faq_editor_reply.html"
        self._context = {
            "is_referee": is_referee,
            "faq_counter": self._get_faq_counter(contest, is_referee),
            'contest': contest,
            'type': 'faq',
            'faq': faq[0]
        }

    def faq_save_new_msg(self, contest_id):
        """
        保存提问、公告
        :param contest_id:

        :return:
        """
        self._action = kernel.const.VIEW_ACTION_JSON

        if not self._check_login(True):
            return

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists(True)
            return

        if not self._check_permission(contest):
            self._send_error_contest_permission_denied(True)
            return

        is_referee = self._check_admin_permission(contest)

        subject = self._request.POST.get("subject", "")
        content = self._request.POST.get("content", "")
        if subject.strip() == '':
            self._result = kernel.RESTStruct(False, "请输入主题")
            return
        if content.strip() == '':
            self._result = kernel.RESTStruct(False, "请输入内容")
            return

        faq = ContestModel.FAQ()
        faq.subject = subject
        faq.content = content
        faq.contest = contest
        faq.author = self._user_session.entity
        if is_referee:
            faq.is_notice = True
            faq.is_private = False
        faq.create_time = int(time.time())
        faq.save()
        self._result = kernel.RESTStruct(True)

    def faq_save_reply(self, contest_id, faq_id):
        """
        保存回复问答
        :param contest_id:

        :return:
        """
        self._action = kernel.const.VIEW_ACTION_JSON

        if not self._check_login(True):
            return

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists(True)
            return

        if not self._check_permission(contest):
            self._send_error_contest_permission_denied(True)
            return

        if not self._check_admin_permission(contest):
            self._send_error_contest_permission_denied(True)
            return

        faq = ContestModel.FAQ.objects.filter(id=faq_id)
        if not faq.exists():
            self._send_error_contest_faq_not_found(True)
            return
        faq = faq[0]

        content = self._request.POST.get("content", "")
        is_public = self._request.POST.get("is_public", "")
        if content.strip() == '':
            self._result = kernel.RESTStruct(False, "请输入回复的内容")
            return
        if is_public == '1':
            is_public = True
        else:
            is_public = False

        faq.answer_content = content
        faq.answer_referee = self._user_session.entity
        faq.answer_time = int(time.time())
        faq.is_private = not is_public
        faq.save()

        self._result = kernel.RESTStruct(True)

    def faq_del(self, contest_id):
        """
        删除提问、公告
        :param contest_id:

        :return:
        """
        self._action = kernel.const.VIEW_ACTION_JSON

        if not self._check_login(True):
            return

        contest = self._get_contest(contest_id)
        if contest is None:
            self._send_error_contest_doesnt_exists(True)
            return

        if not self._check_permission(contest):
            self._send_error_contest_permission_denied(True)
            return

        is_referee = self._check_admin_permission(contest)
        faq_id = self._request.GET.get('id', '')
        try:
            faq_id = int(faq_id)
        except:
            return

        faq = ContestModel.FAQ.objects.filter(id=faq_id)
        if not faq.exists():
            self._result = kernel.RESTStruct(False, "问答内容不存在")
            return
        faq = faq[0]

        if is_referee:
            faq.delete()
        else:
            if self._user_session.user_id == faq.author.id:
                if faq.answer_time != 0:
                    self._result = kernel.RESTStruct(False, "您的问题已经被回复，不能删除！")
                    return
                faq.delete()
            else:
                self._result = kernel.RESTStruct(False, "非法操作")
                return

        self._result = kernel.RESTStruct(True)
